package com.matt.sooncleaner.arch.widget

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import androidx.core.animation.doOnEnd
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import com.matt.sooncleaner.R
import com.matt.sooncleaner.arch.dp
import kotlin.math.min
import kotlin.math.roundToInt

class ProgressView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    private var mMax = resources.getInteger(R.integer.launcher_progress_max).toFloat()
    private val mProgressBackground = RoundedBitmapDrawableFactory.create(resources,
        BitmapFactory.decodeResource(resources, R.drawable.bg_progress)).apply {
            cornerRadius = intrinsicHeight/2f
    }
    private val mProgressHeight = mProgressBackground.intrinsicHeight
    //    private val mBackgroundBounds = RectF(0f, 0f, 0f, mProgressHeight.toFloat())
    private val mProgressBounds = RectF(0f, 0f, 0f, mProgressHeight.toFloat())
    private var mProgressWidth = 0
    private val mRadius = mProgressHeight / 2f
    private val mBgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        setColor(Color.parseColor("#EFEEEE"))
    }
    private val mProgressPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        setColor(resources.getColor(R.color.colorProgress))
    }

    private val mCircleStrokeSize = 1f.dp
    private val mCircleSize = 32f.dp
    private val mCircleRect = RectF(0f, 0f, mCircleSize, mCircleSize)
    private val mInnerCirclePadding = 2f.dp
    private val mCirclePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        setColor(resources.getColor(R.color.colorProgress))
    }
    private val mCircleMarginBottom = 4.dp

    private val mIndicatorMarginBottom = 7.dp
    private val mArrowDrawable = resources.getDrawable(R.drawable.ic_progress_indicator_arrow)
    private val mIndicatorTextBounds = Rect()
    private val mIndicatorTextPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        setColor(resources.getColor(R.color.white))
        textAlign = Paint.Align.CENTER
        textSize = 12f.dp
    }

    private var mIsShowZero = true
    private var mProgress = 0f
    private var mProgressAnimDuration = 5000L
    private var mProgressAnimator: ValueAnimator? = null
    private var mProgressEndListener: (()->Unit)? = null

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val height =
            mProgressHeight + mArrowDrawable.intrinsicHeight +
                    mIndicatorMarginBottom + mCircleSize + mCircleMarginBottom + mCircleStrokeSize
        updateProgressBounds()
        setMeasuredDimension(
            width,
            MeasureSpec.makeMeasureSpec(height.roundToInt(), MeasureSpec.EXACTLY)
        )
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        updateProgressBounds()
    }

    private fun updateProgressBounds() {
        mProgressWidth = width - paddingRight - paddingLeft
//        mBackgroundBounds.right = mProgressWidth.toFloat()
    }

    private fun calculateProgressRight(progress: Float): Float {
        return min(progress, mMax) / mMax * mProgressWidth
    }

    fun setShowZero(isShowZero: Boolean) {
        mIsShowZero = isShowZero
    }

    fun setProgressEndListener(listener: (()->Unit)?) {
        mProgressEndListener = listener
    }

    fun setMax(max: Float) {
        if (mMax == max) {
            return
        }
        mMax = max
        if (width > 0) {
            updateProgressBounds()
        }
    }

    fun getMax() = mMax

    fun setProgressAnimationDuration(duration: Long) {
        mProgressAnimDuration = duration
    }

    fun setProgress(progress: Float, isAnim: Boolean = true) {
        mProgressAnimator?.removeAllUpdateListeners()
        mProgressAnimator?.removeAllListeners()
        mProgressAnimator?.cancel()
        if (isAnim) {
            startProgressAnimation(progress)
        } else {
            mProgress = progress
        }
    }

    fun startProgressAnimation(progress: Float = mMax) {
        mProgressAnimator = ValueAnimator.ofFloat(mProgress, progress)
            .setDuration(mProgressAnimDuration)
        mProgressAnimator?.addUpdateListener {
            mProgress = it.animatedValue as Float
            invalidate()
        }
        mProgressAnimator?.doOnEnd {
            mProgressEndListener?.invoke()
        }
        mProgressAnimator?.start()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        mProgressAnimator?.let {
            it.removeAllUpdateListeners()
            it.removeAllListeners()
            it.cancel()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val left = paddingLeft.toFloat()
        val top = height - mProgressHeight
        canvas.save()
        canvas.translate(left, top.toFloat())
        mProgressBackground.setBounds(0, 0, mProgressWidth, mProgressBackground.intrinsicHeight)
        mProgressBackground.draw(canvas)
//        canvas.drawRoundRect(mBackgroundBounds, mRadius, mRadius, mBgPaint)
        drawProgress(canvas)
        canvas.restore()

        drawIndicator(canvas)
    }

    private fun drawProgress(canvas: Canvas) {
        mProgressBounds.right = calculateProgressRight(mProgress)
        canvas.drawRoundRect(mProgressBounds, mRadius, mRadius, mProgressPaint)
    }

    private fun drawIndicator(canvas: Canvas) {
        if (!mIsShowZero && mProgress.toInt() == 0) return
        drawCircle(canvas)
        drawText(canvas)
        // 绘制下面的箭头
        val left = (mCircleRect.centerX() - mArrowDrawable.intrinsicWidth / 2)
        val top = (mCircleRect.bottom + mCircleMarginBottom).roundToInt()
        mArrowDrawable.setBounds(
            left.roundToInt(),
            top,
            (left + mArrowDrawable.intrinsicWidth).roundToInt(),
            top + mArrowDrawable.intrinsicHeight
        )
        mArrowDrawable.draw(canvas)
    }

    private fun drawCircle(canvas: Canvas) {
        val half = mCircleStrokeSize / 2
        val outerCircleSize = mCircleSize - half
        var outerCircleLeft = mProgressBounds.right + mCircleSize/2f - mRadius
//        outerCircleLeft = max(outerCircleLeft, paddingLeft/2f)
        mCircleRect.set(
            outerCircleLeft,
            mCircleStrokeSize,
            outerCircleLeft + outerCircleSize,
            mCircleStrokeSize + outerCircleSize
        )
        mCirclePaint.style = Paint.Style.STROKE
        mCirclePaint.strokeWidth = mCircleStrokeSize
        canvas.drawCircle(
            mCircleRect.centerX(),
            mCircleRect.centerY(),
            mCircleSize / 2f,
            mCirclePaint
        )

        mCircleRect.inset(mInnerCirclePadding, mInnerCirclePadding)
        mCirclePaint.style = Paint.Style.FILL
        mCirclePaint.strokeWidth = 0f
        canvas.drawCircle(
            mCircleRect.centerX(),
            mCircleRect.centerY(),
            mCircleRect.width() / 2f,
            mCirclePaint
        )
    }

    private fun drawText(canvas: Canvas) {
        val text = "${mProgress.toInt()}%"
        mIndicatorTextPaint.getTextBounds(text, 0, text.length, mIndicatorTextBounds)
        val tx = mCircleRect.centerX()
        val ty = mCircleRect.centerY() - mIndicatorTextBounds.centerY()
        canvas.drawText(text, tx, ty, mIndicatorTextPaint)
    }
}